package com.yanqu.road.server.gameplayer.module.player;

import com.alibaba.fastjson.JSON;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.ActivityRemainTime;
import com.yanqu.road.entity.activity.SystemRemainTime;
import com.yanqu.road.entity.activity.args.RechargeVipArgs;
import com.yanqu.road.entity.config.goods.OpenGoodsBagResult;
import com.yanqu.road.entity.config.player.DecorationInfo;
import com.yanqu.road.entity.config.system.SystemOpenInfo;
import com.yanqu.road.entity.curio.enums.eCurioConditionType;
import com.yanqu.road.entity.enums.activity.eNewServerWelfareActivityType;
import com.yanqu.road.entity.enums.*;
import com.yanqu.road.entity.event.EventTriggerArgs;
import com.yanqu.road.entity.location.LocationInfo;
import com.yanqu.road.entity.log.*;
import com.yanqu.road.entity.messageSubscribe.entity.MessageSubscribePlayerData;
import com.yanqu.road.entity.player.*;
import com.yanqu.road.entity.recharge.RechargeTriggerArgs;
import com.yanqu.road.entity.servercenter.*;
import com.yanqu.road.entity.union.UnionInfo;
import com.yanqu.road.entity.union.UnionMember;
import com.yanqu.road.entity.union.cross.CrossUnionInfo;
import com.yanqu.road.entity.union.cross.CrossUnionMember;
import com.yanqu.road.logic.bussiness.player.UserBussiness;
import com.yanqu.road.logic.bussiness.player.UserHistoryAttributeBussiness;
import com.yanqu.road.logic.bussiness.player.UserSystemInfoBussiness;
import com.yanqu.road.logic.bussiness.player.UserTitleUpgradeBussiness;
import com.yanqu.road.logic.config.ChannelConfig;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.config.ServerConfig;
import com.yanqu.road.logic.pb.CrossGroupPb;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.logic.redis.RedisManger;
import com.yanqu.road.pb.badge.BadgeProto;
import com.yanqu.road.pb.common.ConfigProto;
import com.yanqu.road.pb.decoration.DecorationProto;
import com.yanqu.road.pb.player.PlayerProto;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.activity.businessreunion.BusinessReunionActivityModule;
import com.yanqu.road.server.gameplayer.module.activity.curio.CurioModule;
import com.yanqu.road.server.gameplayer.module.activity.qqprivilege.QQPrivilegeActivityModule;
import com.yanqu.road.server.gameplayer.module.activity.recallplayer.RecallPlayerModule;
import com.yanqu.road.server.gameplayer.module.banquet.BanquetModule;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.creditpoints.CreditPointsModule;
import com.yanqu.road.server.gameplayer.module.minibind.WechatBindModule;
import com.yanqu.road.server.gameplayer.module.patrons.PatronsModule;
import com.yanqu.road.server.gameplayer.module.zhaoshang.ZsModule;
import com.yanqu.road.server.helper.SignHelper;
import com.yanqu.road.server.logic.activity.condition.coupon.CouponNotifyArgs;
import com.yanqu.road.server.logic.activity.condition.recharge.potential.PotentialArg;
import com.yanqu.road.server.logic.mail.MailManager;
import com.yanqu.road.server.logic.system.BaseSystemOpen;
import com.yanqu.road.server.manger.*;
import com.yanqu.road.server.manger.activity.NormalActivityMgr;
import com.yanqu.road.server.manger.activity.TurntableMgr;
import com.yanqu.road.server.manger.activity.curio.CurioMgr;
import com.yanqu.road.server.manger.activity.newserverwelfare.NewServerWelfareMgr;
import com.yanqu.road.server.manger.activity.orewar.OreWarActivityRankMgr;
import com.yanqu.road.server.manger.activity.orewar.OreWarMgr;
import com.yanqu.road.server.manger.activity.seacraft.SeacraftSouthSeaMgr;
import com.yanqu.road.server.manger.analyze.AnalyzeMgr;
import com.yanqu.road.server.manger.config.GoodsBagMgr;
import com.yanqu.road.server.manger.config.GoodsMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.config.TitleMgr;
import com.yanqu.road.server.manger.location.LocationMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.manger.mammon.MammonTypeSwitchMgr;
import com.yanqu.road.server.manger.messagesubscribe.MessageSubscribeMgr;
import com.yanqu.road.server.manger.monopolymarket.MonopolyMarketMgr;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.server.manger.player.PlayerInfoChangeNotifyMgr;
import com.yanqu.road.server.manger.player.UserMgr;
import com.yanqu.road.server.manger.player.WhiteListLocationMgr;
import com.yanqu.road.server.manger.player.task.PlayInfoChangeType;
import com.yanqu.road.server.manger.rank.RankMgr;
import com.yanqu.road.server.manger.systemgroup.newmonopolymarket.NewMonopolyMarketMgr;
import com.yanqu.road.server.manger.union.CrossUnionMgr;
import com.yanqu.road.server.manger.union.UnionActivityMgr;
import com.yanqu.road.server.pb.PlayerPb;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.LocalDateTimeHelper;
import com.yanqu.road.utils.http.HttpHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;
import io.netty.util.internal.StringUtil;

import java.math.BigInteger;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class PlayerModule extends GeneralModule {

    private UserInfo userInfo;

    private UserHistoryAttribute userHistoryAttribute;

    private List<BaseSystemOpen> systemOpenList = new ArrayList<>();

    private Map<Integer, ActivityRemainTime> activityRemainTimeMap = new ConcurrentHashMap<>();

    private Map<Integer, Map<Integer, SystemRemainTime>> systemRemainTimeMap = new ConcurrentHashMap<>();

    private Map<Integer, UserTitleUpgrade> userTitleUpgradeMap;
    private Map<Integer, UserSystemInfo> userSystemInfoMap;

    public PlayerModule(GamePlayer player) {
        super(player);
    }

    public void setUserInfo(UserInfo userInfo) {
        this.userInfo = userInfo;
    }

    @Override
    public boolean loadData() {
        activityRemainTimeMap = new ConcurrentHashMap<>();
        systemRemainTimeMap = new ConcurrentHashMap<>();
        userInfo = player.getUserInfo();
        userHistoryAttribute = UserHistoryAttributeBussiness.getUserHistoryAttribute(player.getUserId());
        userTitleUpgradeMap = UserTitleUpgradeBussiness.getUserTitleUpgradeMap(player.getUserId());
        userSystemInfoMap = UserSystemInfoBussiness.getUserSystemInfoMap(player.getUserId());
        initUserHistoryAttribute();
        initSystemOpen();
        checkValid();
        return true;
    }

    @Override
    public boolean afterLoadData() {
        UserMgr.checkPlayerDecorationOverTime(player.getUserInfo(), false);

        checkUserProvince();
        return true;
    }

    private void checkUserProvince() {
        try {
            List<String> provinceList = StringUtils.stringToStringList("河北,山西,辽宁,吉林,黑龙江,江苏,浙江,安徽,福建,江西,山东,河南,湖北,湖南,广东,海南,四川,贵州,云南,陕西,甘肃,青海", ",");
            ServerInfo serverInfo = ServerListMgr.getServerInfo(GameServer.getInstance().getServerId());
            if (serverInfo != null) {
                if (eChannelType.isMainLandChannel(serverInfo.getChannelId())) {
                    if (provinceList.contains(userInfo.getProvince())) {
                        userInfo.setProvince(userInfo.getProvince() + "省");
                        UserMgr.getLogger().debug("update user {} province {}", player.getUserId(), userInfo.getProvince());
                    }
                }
            }
        }catch (Exception e){
            UserMgr.getLogger().error(e.getMessage());
        }
    }

    @Override
    public boolean saveData() {
        if (null != userInfo && userInfo.isUpdateOption()) {
            UserBussiness.updateUserInfo(userInfo);
        }
        if(null != userHistoryAttribute){
            if(userHistoryAttribute.isInsertOption()){
                UserHistoryAttributeBussiness.addUserHistoryAttribute(userHistoryAttribute);
            }else if(userHistoryAttribute.isUpdateOption()){
                UserHistoryAttributeBussiness.updateUserHistoryAttribute(userHistoryAttribute);
            }
        }
        for(UserTitleUpgrade data : userTitleUpgradeMap.values()){
            if(data.isInsertOption()){
                UserTitleUpgradeBussiness.addUserTitleUpgrade(data);
            }
        }
        for(UserSystemInfo data : userSystemInfoMap.values()){
            if(data.isInsertOption()){
                UserSystemInfoBussiness.addUserSystemInfo(data);
            }else if(data.isUpdateOption()){
                UserSystemInfoBussiness.updateUserSystemInfo(data);
            }
        }
        return true;
    }

    @Override
    public void printErrorSqlDataFromMemory() {
        if (userInfo != null && userInfo.isUpdateOption()) {

        }
    }

    @Override
    public void loginSendMsg() {
        checkNickName();
        UserMgr.checkPlayerDecorationOverTime(player.getUserInfo(), false);
        PlayerProto.PlayerDataTempMsg.Builder msg = PlayerPb.parsePlayerDataTempMsg(userInfo, player.getModule(AttributeModule.class).getUserAttributeMap());
        if(null != msg) {
            player.sendPacket(Protocol.U_PLAYER_DATA, msg);
        }
        syncChannelConfig();
        syncServerConfig();
        syncGameConfig();
        syncSystemOpen();
        syncUserHistoryAttribute();
        syncServerGroup();
        syncMarriageGroup();
        syncAreaMammonGroup();
        MammonTypeSwitchMgr.syncMammonTypeSwitch(player);
        syncExpressionShielding();
    }

    @Override
    public void afterLogin() {
        syncSystemInfo(new ArrayList<>(userSystemInfoMap.values()), true);
        // 处理下订阅相关的信息，需要记录登录的 app_ext，用于透传给37
        MessageSubscribePlayerData userData = MessageSubscribeMgr.getUserData(player.getUserId());
        if (userData == null) {
            return;
        }
        String appExt = "";
        if (player.getAppExt().containsKey("app_ext")) {
            appExt = player.getAppExt().getString("app_ext");
        }
        userData.setAppExt(appExt);

        // 非寒冬特色服 主角切换为默认男性形象第一个
        boolean isIceServer = ConfigMgr.isTargetSpecialServer(eSpecialServerType.IceServer);
        if (!isIceServer) {
            String decoration = userInfo.getDecoration();
            List<Integer> dataList = StringUtils.stringToIntegerList(decoration, DecorationMgr.SPLIT_SEPARATOR);
            // 寒冬特色服主角头像和服饰
            int headIconPos = eDecorationType.HeadIcon.getValue();
            int costumePos = eDecorationType.Costume.getValue();
            if (GameConfig.ICE_SERVER_PLAYER_DEC_KEY.contains(String.valueOf(dataList.get(headIconPos)))
                    || GameConfig.ICE_SERVER_PLAYER_DEC_KEY.contains(String.valueOf(dataList.get(costumePos)))) {
                List<DecorationInfo> headIconFrees = DecorationMgr.getMaleFreeDecorationList(headIconPos);
                List<DecorationInfo> costumeFrees = DecorationMgr.getMaleFreeDecorationList(costumePos);
                if (headIconFrees.size() > 1 && !costumeFrees.isEmpty()) {
                    DecorationInfo headIconInfo = headIconFrees.get(1);
                    if (headIconInfo == null) {
                        return;
                    }
                    DecorationInfo costumeInfo = costumeFrees.get(0);
                    if (costumeInfo == null) {
                        return;
                    }
                    // 改头
                    changeDecoration(eDecorationType.HeadIcon.getValue(), headIconInfo.getId(), true);
                    // 身体形象
                    changeDecoration(eDecorationType.Costume.getValue(), costumeInfo.getId(), true);
                    DecorationProto.ChangeRoleRespMsg.Builder respMsg = DecorationProto.ChangeRoleRespMsg.newBuilder();
                    respMsg.setRet(0);
                    respMsg.setDecoration(player.getUserInfo().getDecoration());
                    player.sendPacket(Protocol.U_CHANGE_ROLE, respMsg);
                } else {
                    log.error("角色头像、服饰默认配置错误");
                }
            }
        }
    }

    private void checkNickName() {
        //检查昵称
        String nickName = StringUtils.clearHeadAndTailEmpty(userInfo.getNickName());
        if (!Objects.equals(userInfo.getNickName(),nickName)) {
            player.getModule(PlayerModule.class).setNickName(nickName);
        }
    }

    public void syncServerGroup(){
        ServerInfo serverInfo = ServerListMgr.getServerInfo(GameServer.getInstance().getServerId());
        if(null != serverInfo) {
            player.sendPacket(Protocol.U_CROSS_GROUP_SYNC, CrossGroupPb.parseCrossGroupListMsg(ServerGroupMgr.getServerGroupList(serverInfo.getChannelId())));
            player.sendPacket(Protocol.U_CROSS_GROUP_SYNC_NEW, CrossGroupPb.parseCrossGroupTypeListMsg(CrossServerGroupMgr.getServerGroupList(serverInfo.getChannelId())));
        }
    }

    public void syncAreaMammonGroup() {
        ServerGroup2 serverGroup2 = ServerGroup2Mgr.getServerGroup2(eServerGroup2Type.CrossAreaMammon, GameServer.getInstance().getServerId());
        player.sendPacket(ClientProtocol.U_MAMMON_AREA_GROUP_SYNC, CrossGroupPb.parseAreaMammonGroupMsg(serverGroup2));
    }

    /**
     * 同步跨服联姻分组
     */
    public void syncMarriageGroup(){
        int channelId = ServerListMgr.getChannelId(GameServer.getInstance().getServerId());
        player.sendPacket(Protocol.U_CROSS_MARRIAGE_GROUP_SYNC, CrossGroupPb.parseCrossMarriageGroupListMsg(CrossMarriageGroupMgr.getCrossMarriageGroupList(channelId)));
    }

    /**
     * 同步跨服联姻分组
     */
    public void syncPartyGroup(){
        int channelId = ServerListMgr.getChannelId(GameServer.getInstance().getServerId());
        player.sendPacket(Protocol.U_CROSS_MARRIAGE_GROUP_SYNC, CrossGroupPb.parseCrossMarriageGroupListMsg(CrossMarriageGroupMgr.getCrossMarriageGroupList(channelId)));
    }

    private void checkValid(){
        if(!CrossUnionMgr.isAllSync()){
            return;
        }
        String unionUid = "";
        UnionMember unionMember = CrossUnionMgr.getUnionMember(player.getUserId());
        if(null != unionMember){
            unionUid = unionMember.getUnionUid();
        }else {
            unionMember = CrossUnionMgr.getUnionMember("", player.getUserId());
            if(unionMember != null){
                unionUid = unionMember.getUnionUid();
            }
        }
        if(!Objects.equals(unionUid, userInfo.getUnionUid())) {
            userInfo.setUnionUid(unionUid);
            UserMgr.addNeedUpdateToCrossMap(player.getUserId(), userInfo);
        }
        if(!StringUtils.isNullOrEmpty(unionUid)){
            UnionInfo unionInfo = CrossUnionMgr.getUnionInfo(unionUid);
            if(null == unionInfo){//商会已解散
                //CrossUnionMgr.playerCheckUnionValid(player);
                userInfo.setUnionUid("");
                CrossUnionMember member = CrossUnionMgr.getUnionMember(unionUid, player.getUserId());
                if(null != member){
                    member.setUnionUid("");
                    CrossUnionMgr.addMemberToDeleteMap(member);
                }
            }
        }
    }

    public void syncExpressionShielding() {
        ConfigProto.ExpressionShieldingconfigMsg.Builder msg = ConfigProto.ExpressionShieldingconfigMsg.newBuilder();
        if (StringUtils.isNullOrEmpty(ChannelConfig.EXPRESSION_SHIELDING)) {
            player.sendPacket(ClientProtocol.U_EXPRESSION_SHIELDING, msg);
            return;
        }
        String[] arr = ChannelConfig.EXPRESSION_SHIELDING.split(",");
        for (String s : arr) {
            msg.addExpressionType(Integer.parseInt(s));
        }
        player.sendPacket(ClientProtocol.U_EXPRESSION_SHIELDING, msg);
    }

    public void syncChannelConfig() {
        boolean useReview = false;
        int channelId = ServerListMgr.getChannelId(GameServer.getInstance().getServerId());
        ServerInfo serverInfo = ServerListMgr.getServerInfo(GameServer.getInstance().getServerId());
        if(eChannelType.isMainLandChannel(channelId)){
            if(null != serverInfo && serverInfo.getServerType() == ServerListMgr.SERVER_TYPE_REVIEW){//提审服用提审配置
                useReview = true;
            }
        }
        ConfigProto.ChannelConfigDataMsg.Builder msg = ConfigProto.ChannelConfigDataMsg.newBuilder();
        msg.setSettingSwitch(ChannelConfig.SETTING_SWITCH);
        msg.setIsYjxmLinkage(ChannelConfig.YJXM_LINKAGE_SWITCH == 1);
        msg.setIsYjsyLinkage(ChannelConfig.YJSY_LINKAGE_SWITCH == 1);       //阳际山野联动开关
        msg.setCustomerButtonShow(ChannelConfig.CUSTOMER_BUTTON_SHOW);
        msg.setIsVehicleRecycleLock(ChannelConfig.VEHICLE_RECYCLE_LOCK == 1);
        if(useReview){
            msg.setBuildingSkin(ChannelConfig.BUILDING_SKIN_SWITCH_REVIEW);
            msg.setIsCpSLinkage(ChannelConfig.CPS_LINKAGE_SWITCH_REVIEW == 1);
            msg.setLinleeLinkageSwitch(ChannelConfig.LIN_LEE_LINKAGE_SWITCH_REVIEW);
            msg.setHalloThemeWeenSwitch(ChannelConfig.HALLOWEEN_THEME_OPEN_SWITCH_REVIEW);
            msg.setZjBeerLinkageSwitch(ChannelConfig.ZJ_DEER_LINKAGE_SWITCH_REVIEW);
            msg.setNowWaLinkageSwitch(ChannelConfig.NOW_WA_LINKAGE_SWITCH_REVIEW);
            msg.setMeiTuanLinkageSwitch(ChannelConfig.MEI_TUAN_LINKAGE_SWITCH_REVIEW);
        }else {
            msg.setBuildingSkin(ChannelConfig.BUILDING_SKIN_SWITCH);
            msg.setIsCpSLinkage(ChannelConfig.CPS_LINKAGE_SWITCH == 1);
            msg.setLinleeLinkageSwitch(ChannelConfig.LIN_LEE_LINKAGE_SWITCH);
            msg.setHalloThemeWeenSwitch(ChannelConfig.HALLOWEEN_THEME_OPEN_SWITCH);
            msg.setZjBeerLinkageSwitch(ChannelConfig.ZJ_DEER_LINKAGE_SWITCH);
            msg.setNowWaLinkageSwitch(ChannelConfig.NOW_WA_LINKAGE_SWITCH);
            msg.setMeiTuanLinkageSwitch(ChannelConfig.MEI_TUAN_LINKAGE_SWITCH);
        }
        msg.setWeekCardSwitch(ChannelConfig.WEEK_CARD_SWITCH);
        msg.setDestroyRoleSwitch(ChannelConfig.DESTROY_ROLE_SWITCH);

        // 取下商铺皮肤, 有特色服取特色服，没特色服取普通服，没普通服取默认
        int realtyMainSkin = ChannelConfig.REALTY_MAIN_SKIN_DEFAULT;
        boolean isSpecialServer = false;
        int normalServerRealtyMainSkin = realtyMainSkin;
        if (!StringUtils.isNullOrEmpty(ChannelConfig.REALTY_MAIN_SKIN_PARAM)) {
            List<String> realtyMainSkinParamList = StringUtils.stringToStringList(ChannelConfig.REALTY_MAIN_SKIN_PARAM, "\\|");
            for (String realtyMainSkinParam : realtyMainSkinParamList) {
                String[] split = realtyMainSkinParam.split(",");
                int specialServerType = Integer.parseInt(split[0]);
                int tmpRealtyMainSkin = Integer.parseInt(split[1]);
                if (specialServerType == 0) {
                    // 默认普通服
                    normalServerRealtyMainSkin = tmpRealtyMainSkin;
                }
                if (serverInfo != null && serverInfo.getSpecialServer() == specialServerType) {
                    realtyMainSkin = tmpRealtyMainSkin;
                    isSpecialServer = true;
                }
            }
        }
        msg.setRealtyMainSkin(isSpecialServer ? realtyMainSkin : normalServerRealtyMainSkin);

        if (!StringUtils.isNullOrEmpty(player.getAppId())) {
            //子渠道标识
            AppIdChaneelInfo appIdChaneelInfo = ServerListMgr.getAppIdChaneelInfo(player.getAppId());
            if (appIdChaneelInfo != null) {
                msg.setDestroyRoleSwitch(appIdChaneelInfo.isDestroyRoleLimit() ? 1 : 0);
            }
        }

        msg.setNewYearBagSwitch(ChannelConfig.NEW_YEAR_BAG_SWITCH);

        ConfigProto.ChannelConfigKeyValue.Builder tongBaoVipLimit = ConfigProto.ChannelConfigKeyValue.newBuilder();
        tongBaoVipLimit.setKey("TONG_BAO_BUY_VIP_LIMIT");
        tongBaoVipLimit.setValue(String.valueOf(ChannelConfig.TONG_BAO_BUY_VIP_LIMIT));
        msg.addChannelConfigKeyValue(tongBaoVipLimit);

        ConfigProto.ChannelConfigKeyValue.Builder tongBaoSwitch = ConfigProto.ChannelConfigKeyValue.newBuilder();
        tongBaoSwitch.setKey("TONG_BAO_BUY_SWITCH");
        tongBaoSwitch.setValue(String.valueOf(ChannelConfig.TONG_BAO_BUY_SWITCH));
        msg.addChannelConfigKeyValue(tongBaoSwitch);

        ConfigProto.ChannelConfigKeyValue.Builder iosRechargeWitch = ConfigProto.ChannelConfigKeyValue.newBuilder();
        iosRechargeWitch.setKey("IOS_RECHARGE_SWITCH");
        iosRechargeWitch.setValue(String.valueOf(ChannelConfig.IOS_RECHARGE_SWITCH));
        msg.addChannelConfigKeyValue(iosRechargeWitch);

        ConfigProto.ChannelConfigKeyValue.Builder expressionWitch = ConfigProto.ChannelConfigKeyValue.newBuilder();
        expressionWitch.setKey("EXPRESSION_TYPE_9_SWITCH");
        expressionWitch.setValue(ChannelConfig.EXPRESSION_TYPE_9_SWITCH);
        msg.addChannelConfigKeyValue(expressionWitch);

        ConfigProto.ChannelConfigKeyValue.Builder kowloonOpenDaySwitch = ConfigProto.ChannelConfigKeyValue.newBuilder();
        kowloonOpenDaySwitch.setKey("KOWLOON_OPEN_DAY_SWITCH");
        // 大于这个时间点的才显示天数限制
        kowloonOpenDaySwitch.setValue(serverInfo != null && serverInfo.getOpenTime() >= ChannelConfig.KOWLOON_VERSION_UPDATE_TIMESTAMP ? "1" : "0");
        msg.addChannelConfigKeyValue(kowloonOpenDaySwitch);

        String gameId = player.getModule(WechatBindModule.class).getGameId();
        if(StringUtils.isNullOrEmpty(gameId) || Objects.equals("37wxxyx", player.getAppId())){
            msg.addChannelConfigKeyValue(ConfigProto.ChannelConfigKeyValue.newBuilder().setKey("WX_BIND_IS_OPEN").setValue("0"));
        }else {
            msg.addChannelConfigKeyValue(ConfigProto.ChannelConfigKeyValue.newBuilder().setKey("WX_BIND_IS_OPEN").setValue(String.valueOf(ChannelConfig.WX_BIND_IS_OPEN)));
        }

        ConfigProto.ChannelConfigKeyValue.Builder huiPaiLinkAgeProto = ConfigProto.ChannelConfigKeyValue.newBuilder();
        huiPaiLinkAgeProto.setKey("HUI_PAI_LINKAGE_SWITCH").setValue(String.valueOf(ChannelConfig.HUI_PAI_LINKAGE_SWITCH));
        msg.addChannelConfigKeyValue(huiPaiLinkAgeProto);

        try {
            if (!ChannelConfig.WX_BIND_IS_OPEN.equals("0") && !StringUtils.isNullOrEmpty(gameId)) {
                //跳转码密前参数格式：平台 uid|服 id|角色 id|角色名|区服名|游戏 id
                StringBuilder codeBuilder = new StringBuilder();
                codeBuilder.append(player.getUserInfo().getPlatformUserId()).append("|");
                codeBuilder.append(GameServer.getInstance().getServerId()).append("|");
                codeBuilder.append(player.getUserId()).append("|");
                String encodeNickName = URLEncoder.encode(player.getUserInfo().getNickName(), "UTF-8");
                codeBuilder.append(encodeNickName).append("|");
                String encodeServerName = URLEncoder.encode(serverInfo.getServerName(), "UTF-8");
                codeBuilder.append(encodeServerName).append("|");
                codeBuilder.append(gameId);
                String code = codeBuilder.toString();
                String encryptCode = SignHelper.encryptByAES(code, ChannelConfig.WX_BIND_CODE_SECRET);
                msg.addChannelConfigKeyValue(ConfigProto.ChannelConfigKeyValue.newBuilder().setKey("WX_BIND_SKIP_CODE").setValue(encryptCode));
            }
        } catch (Exception e) {
            log.error("跳转码生成 error" + e);
        }

        //企微小助手
        ConfigProto.ChannelConfigKeyValue.Builder wxXZS = ConfigProto.ChannelConfigKeyValue.newBuilder();
        wxXZS.setKey("WX_XIAOZHUSHOU").setValue(String.valueOf(ChannelConfig.WX_XIAOZHUSHOU));
        msg.addChannelConfigKeyValue(wxXZS);


        player.sendPacket(ClientProtocol.U_CHANNEL_CONFIG_SYNC, msg);
    }

    public void syncServerConfig(){
        ConfigProto.ServerConfigDataMsg.Builder msg = ConfigProto.ServerConfigDataMsg.newBuilder();
        msg.setBeautyUndress(ChannelConfig.BEAUTY_UNDRESS);
        msg.setShowGoodsBagRate(ChannelConfig.SHOW_GOOD_BAG_RATE);
        msg.setGoldTokenSwitch(ServerConfig.GOLD_TOKEN_BUY_SWITCH);
        player.sendPacket(Protocol.U_SERVER_CONFIG_SYNC, msg);
    }

    public void syncGameConfig(){
        ConfigProto.GameConfigDataMsg.Builder msg = ConfigProto.GameConfigDataMsg.newBuilder();
        msg.setServerOpenAfterDaysOpenHunt(GameConfig.SEVER_OPEN_AFTER_DAYS_OPEN_HUNT);
        msg.setServerOpenAfterDaysOpenSacrifice(GameConfig.SEVER_OPEN_AFTER_DAYS_OPEN_SACRIFICE);
        msg.setOneKeyBackendPassRoadLimit(GameConfig.ONE_KEY_BACKEND_PASS_ROAD_LIMIT);
        msg.setGmMailSettings(GameConfig.GM_MAIL_SETTINGS);
        msg.setOneKeyBackendPassRoadVipLimit(GameConfig.ONE_KEY_BACKEND_PASS_ROAD_VIP_LIMIT);
        msg.setOneKeyChildrenAdvancedTrainTitleLimit(GameConfig.CHILDREN_ADVANCED_TRAIN_NEED_TITLE_LIMIT);
        msg.setTurntableMallRegisterTimeLimit(GameConfig.TURNTABLE_MALL_REGISTER_TIME_LIMIT);
        ServerInfo serverInfo = ServerListMgr.getServerInfo(GameServer.getInstance().getServerId());
        if(serverInfo != null) {
            msg.setServerOpenAfterDaysOpenZhaoShang(serverInfo.getOpenZsDay());
        }
        player.sendPacket(Protocol.U_GAME_CONFIG_SYNC, msg);
    }

    public void syncSystemOpen(){
        PlayerProto.SystemOpenMsg.Builder msg = PlayerProto.SystemOpenMsg.newBuilder();
        msg.setValue(player.getUserInfo().getSystemOpenValue().toString(2));
        player.sendPacket(Protocol.U_SYSTEM_OPEN_SYNC, msg);
    }

    public void syncUserHistoryAttribute() {
        PlayerProto.HistoryAttributeMsg.Builder msg = PlayerBasePb.parseHistoryAttributeMsg(userHistoryAttribute);
        if(null != msg){
            player.sendPacket(Protocol.U_HISTORY_ATTRIBUTE_SYNC, msg);
        }
    }

    private void initSystemOpen(){
        List<SystemOpenInfo> dataList = SystemOpenMgr.getSystemOpenInfoList();
        List<BaseSystemOpen> openList = new ArrayList<>();
        for(SystemOpenInfo systemOpenInfo : dataList){
            BaseSystemOpen baseSystemOpen = BaseSystemOpen.createBaseSystemOpen(systemOpenInfo.getSystemId(), player);
            if(null != baseSystemOpen) {
                openList.add(baseSystemOpen);
            }
        }
        systemOpenList = openList;
    }

    private void initUserHistoryAttribute(){
        if(null == userHistoryAttribute){
            UserHistoryAttribute historyAttribute = new UserHistoryAttribute();
            historyAttribute.setUserId(player.getUserId());
            historyAttribute.setAbility(BigInteger.ZERO);
            historyAttribute.setQualification(0);
            historyAttribute.setEarnSpeed(userInfo.getEarnSpeed());
            historyAttribute.setActivityStartAbility(BigInteger.ZERO);
            historyAttribute.setActivityStartEarnSpeed(BigInteger.ZERO);
            historyAttribute.setActivityStartQualification(0);
            historyAttribute.setInsertOption();
            userHistoryAttribute = historyAttribute;
        }
    }

    /**
     * 身份升级
     */
    public int titleUpgrade(){
        long nowTime = System.currentTimeMillis();

        int titleId = userInfo.getTitleId();
        TitleInfo nextTitleInfo = TitleMgr.getTitleInfo(titleId + 1);
        if (null == nextTitleInfo) {
            return GameErrorCode.E_TITLE_LEVEL_MAX;
        }
        TitleInfo titleInfo = TitleMgr.getTitleInfo(titleId);
        //判断升级条件
        if(titleInfo.getNeedEarnSpeed().compareTo(player.getModule(EarnSpeedModule.class).getEarnSpeed()) > 0){
            return GameErrorCode.E_EARN_SPEED_NO_ENOUGH;
        }
        if(titleInfo.getNeedPrestige().compareTo(userInfo.getPrestige()) > 0){
            return GameErrorCode.E_PRESTIGE_NO_ENOUGH;
        }
        //检测一下当日的元宝奖励有没有领取
        checkTitleReward();
        //身份等级增加
        userInfo.setTitleId(userInfo.getTitleId() + 1);
        Property reward = new Property();
        reward.addProperty(titleInfo.getReward());     //通用奖励
        if(player.getUserInfo().getSex() == eSexType.MALE.getValue()){
            reward.addProperty(titleInfo.getMaleReward());
        }else if(player.getUserInfo().getSex() == eSexType.FEMALE.getValue()){
            reward.addProperty(titleInfo.getFemaleReward());
        }
        player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.Title, eLogMoneyType.TitleUpgradeReward);
        //重置奖励领取时间
        player.getModule(AttributeModule.class).setAttribute(ePlayerAttrType.GetTitleRewardTime, 0);
        //成就、任务
        player.notifyListener(eGamePlayerEventType.TitleLevel.getValue(), userInfo.getTitleId());
        //门客基金
        player.notifyListener(eGamePlayerEventType.PatronsFund.getValue(), userInfo.getTitleId());
        //现金礼包
        player.notifyListener(eGamePlayerEventType.RechargeTitle.getValue(), 0);
        //记录身份升级时间
        addUserTitleUpgrade(userInfo.getTitleId(), System.currentTimeMillis() / 1000);

        player.notifyListener(eGamePlayerEventType.RechargePotentialAnd.getValue(), new PotentialArg(false, 0));
        player.notifyListener(eGamePlayerEventType.RechargePotentialOr.getValue(), new PotentialArg(false, 0));

        player.getModule(RecallPlayerModule.class).updateTaskFromSystem(eRecallPlayerConditionTypeEnum.userLevel,BigInteger.valueOf(userInfo.getTitleId()));
        //身份变更
        onTitleChange();
        onUserInfoChange();
        PlayerInfoChangeNotifyMgr.notifyReload(PlayInfoChangeType.Title.getType(), userInfo.getUserId(), new EventTriggerArgs(userInfo.getTitleId()));
        // 是否禁言
        if (player.getModule(CreditPointsModule.class).checkBanned()) {
            // 减少禁言时间
            player.getModule(CreditPointsModule.class).addBannedTime(-GameConfig.CHAT_BLACK_TIME_CUT);
        }
        if(ServerConfig.ANALYZE_USER_LOG > 0) {
            AnalyzeMgr.addUserTitleUpgrade(player, System.currentTimeMillis() / 1000);
        }
        log.info("titleUpgrade cost time:{}ms", System.currentTimeMillis() - nowTime);

        DataAnalyticsMgr.trackTitleUpgrade(player);
        RechargeSwitchConfigMgr.syncRechargeOpenConfig(player);
        player.getModule(BanquetModule.class).syncAutoInfo();
        return 0;
    }

    private void checkTitleReward(){
        long zeroTime = LocalDateTimeHelper.getZeroTimeTimeStamp() / 1000;
        long nowTime = System.currentTimeMillis() / 1000;
        long getTitleRewardTime = player.getModule(AttributeModule.class).getAttribute(ePlayerAttrType.GetTitleRewardTime);
        if (getTitleRewardTime > zeroTime) {
            return;
        }
        TitleInfo titleInfo = TitleMgr.getTitleInfo(userInfo.getTitleId());
        if(titleInfo.getDailyGetIngots() <= 0){
            return;
        }
        //记录领取时间
        player.getModule(AttributeModule.class).setAttribute(ePlayerAttrType.GetTitleRewardTime, nowTime);
        //邮件发送奖励
        //String reward = PropertyHelper.parseGoodsToString(GameConfig.GAME_MONEY_INGOTS, BigInteger.valueOf(titleInfo.getDailyGetIngots()));
        Property property = new Property(GameConfig.GAME_MONEY_INGOTS, BigInteger.valueOf(titleInfo.getDailyGetIngots()));
        property.addProperty(GameConfig.GAME_MONEY_INGOTS, CurioMgr.getSkillAdditionBySkillType(eSkillType.CurioTitleRewardIngotsAddSkill.getValue(), player, 0));
        String mailTitle = MultipleLanguageMgr.getContent(MailManager.TITLE_DAILY_REWARD_TITLE, player.getLanguage());
        String mailContent = MultipleLanguageMgr.getContent(MailManager.TITLE_DAILY_REWARD_CONTENT, player.getLanguage());
        MailManager.sendMail(player.getUserId(), eMailType.SYSTEM.getValue(), PropertyHelper.parsePropertyToString(property), mailContent, mailTitle);
    }

    /**
     * 领取身份每日元宝
     * @return
     */
    public PlayerProto.GetTitleRewardRespMsg.Builder getTitleReward(){
        PlayerProto.GetTitleRewardRespMsg.Builder respMsg = PlayerProto.GetTitleRewardRespMsg.newBuilder();
        long zeroTime = LocalDateTimeHelper.getZeroTimeTimeStamp() / 1000;
        long nowTime = System.currentTimeMillis() / 1000;
        long getTitleRewardTime = player.getModule(AttributeModule.class).getAttribute(ePlayerAttrType.GetTitleRewardTime);
        if (getTitleRewardTime > zeroTime) {
            respMsg.setRet(GameErrorCode.E_TITLE_REWARD_IS_GET);
            return respMsg;
        }
        //记录领取时间
        player.getModule(AttributeModule.class).setAttribute(ePlayerAttrType.GetTitleRewardTime, nowTime);
        //发送奖励
        TitleInfo titleInfo = TitleMgr.getTitleInfo(userInfo.getTitleId());
        Property property = new Property(GameConfig.GAME_MONEY_INGOTS, BigInteger.valueOf(titleInfo.getDailyGetIngots()));
        property.addProperty(GameConfig.GAME_MONEY_INGOTS, CurioMgr.getSkillAdditionBySkillType(eSkillType.CurioTitleRewardIngotsAddSkill.getValue(), player, 0));
        player.getModule(CurrencyModule.class).addCurrency(property,
                eLogMoneyType.Title, eLogMoneyType.TitleGetReward);
        respMsg.setRet(0);
        respMsg.setGetRewardTime(nowTime);
        respMsg.setReward(PropertyHelper.parsePropertyToString(property));

        player.getModule(CurioModule.class).addUserCurioCountData(eCurioConditionType.GetTitleRewardTimes.getType(), 1);
        return respMsg;
    }

    public void syncDecoration(){
        onUserInfoChange();
    }

    public void addVipExp(long addVipExp){
        if(addVipExp > 0) {
            userInfo.setVipExp(userInfo.getVipExp() + addVipExp);
            player.getModule(AttributeModule.class).syncAttribute(ePlayerAttrType.VipExp);
            player.notifyListener(eGamePlayerEventType.VipExp.getValue(), userInfo.getVipExp());
            player.notifyListener(eGamePlayerEventType.SpringBanquetVip.getValue(), addVipExp);
            player.notifyListener(eGamePlayerEventType.HistoryRechargeVipExpDay.getValue(), null);
            player.notifyListener(eGamePlayerEventType.FirstRechargeVipExpDay.getValue(), null);
            player.notifyListener(eGamePlayerEventType.RechargeVipExpDay.getValue(), new RechargeVipArgs(addVipExp, 0));
            player.notifyListener(eGamePlayerEventType.RechargeTrigger.getValue(), new RechargeTriggerArgs(addVipExp));
            player.notifyListener(eGamePlayerEventType.RoundVipExp.getValue(), addVipExp);
            int vipLv = VipMgr.getVipLv(userInfo.getVipExp());
            player.notifyListener(eGamePlayerEventType.VipLevel.getValue(), vipLv);
            player.getModule(BusinessReunionActivityModule.class).addVipExp(addVipExp);
            //汴梁达人同步任务
            player.getModule(RecallPlayerModule.class).updateTaskFromSystem(eRecallPlayerConditionTypeEnum.rechargeAfterBind,BigInteger.valueOf(addVipExp));
            // VIP达到配置等级解除玩家禁言
            if (vipLv >= GameConfig.CHAT_BLACK_SAFE) {
                player.getModule(CreditPointsModule.class).removeBanned();
            }
            AttributeModule attributeModule = player.getModule(AttributeModule.class);
            //记录首次充值时间
            long firstRechargeTime = attributeModule.getAttribute(ePlayerAttrType.FirstRechargeTime);
            if(firstRechargeTime <= 0){
                attributeModule.setAttribute(ePlayerAttrType.FirstRechargeTime, System.currentTimeMillis() / 1000);
            }
            onUserInfoChange();

            //充值埋点
            DataAnalyticsMgr.allRechargeInfo(player);
        }
    }

    //后台修改vip经验，只影响vip等级，不涉及每日储值和累计储值
    public void changeVipExpBackend(int vipExp){
        long originalValue = userInfo.getVipExp();
        if(userInfo.getVipExp() + vipExp < 0){
            userInfo.setVipExp(0);
        }else{
            userInfo.setVipExp(userInfo.getVipExp() + vipExp);
        }
        player.getModule(AttributeModule.class).syncAttribute(ePlayerAttrType.VipExp);
        player.notifyListener(eGamePlayerEventType.VipExp.getValue(), userInfo.getVipExp());
        player.notifyListener(eGamePlayerEventType.SpringBanquetVip.getValue(), (long)vipExp);
        player.notifyListener(eGamePlayerEventType.VipLevel.getValue(), VipMgr.getVipLv(userInfo.getVipExp()));
        player.getModule(BusinessReunionActivityModule.class).addVipExp(vipExp);
        player.getModule(RecallPlayerModule.class).updateTaskFromSystem(eRecallPlayerConditionTypeEnum.rechargeAfterBind,BigInteger.valueOf(userInfo.getVipExp()));
        onUserInfoChange();
        AutoLogMgr.add(new LogVipExp(player.getUserId(), originalValue, vipExp, originalValue + vipExp < 0 ? 0 : originalValue + vipExp, 0, "后台修改vip经验"));
    }

    //累计充值的后台接口
    public void changeTotalRechargeBackend(int vipExp){
        long original = player.getModule(AttributeModule.class).getAttribute(ePlayerAttrType.DayTotalRecharge);
        if(original + vipExp < 0){
            player.getModule(AttributeModule.class).setAttribute(ePlayerAttrType.DayTotalRecharge, 0);
        }else{
            player.getModule(AttributeModule.class).addAttribute(ePlayerAttrType.DayTotalRecharge, vipExp);
        }
        long notifyArgs = vipExp;
        player.notifyListener(eGamePlayerEventType.BackendTotalRecharge.getValue(), notifyArgs);
    }

    //每日充值的后台接口
    public void changeDayRechargeBackend(int vipExp){
        long original = player.getModule(AttributeModule.class).getAttribute(ePlayerAttrType.DayTotalRecharge);
        if(original + vipExp < 0){
            player.getModule(AttributeModule.class).setAttribute(ePlayerAttrType.DayTotalRecharge, 0);
        }else{
            player.getModule(AttributeModule.class).addAttribute(ePlayerAttrType.DayTotalRecharge, vipExp);
        }
        long notifyArgs = vipExp;
        player.notifyListener(eGamePlayerEventType.BackendDayRecharge.getValue(), notifyArgs);
    }

    public UserInfo getUserInfo() {
        return userInfo;
    }

    public UserHistoryAttribute getUserHistoryAttribute() {
        return userHistoryAttribute;
    }

    public void setPosition(String world, String continent, String country, String province, String city) {
        userInfo.setWorld(world);
        userInfo.setContinent(continent);
        userInfo.setCountry(country);
        userInfo.setProvince(province);
        userInfo.setCity(city);
        onUserInfoChange();
    }

    public void setNickName(String nickName) {
        userInfo.setNickName(nickName);
        onUserInfoChange();
//        player.getModule(ActivityModule.class).nickNameChange();
//        player.getModule(CommonActivityModule.class).nickNameChange();
//        player.getModule(OreWarActivityModule.class).nickNameChange();
    }

    public void setProvince(String province){
        userInfo.setProvince(province);
        onUserInfoChange();
    }

    public void setCity(String city){
        userInfo.setCity(city);
        onUserInfoChange();
    }

    public void setLanguage(String language) {
        userInfo.setLanguage(language);
    }

    public void setIp(String ip) {
        if (StringUtil.isNullOrEmpty(userInfo.getCity())) {
            int channelId = 0;
            ServerInfo serverInfo = ServerListMgr.getServerInfo(GameServer.getInstance().getServerId());
            if(null != serverInfo) {
                channelId = serverInfo.getChannelId();
            }
            //港澳台、韩国、日本渠道不用ip定位地理信息，直接使用默认地理信息
            if (LocationMgr.isUseDefaultLocation(channelId)) {
                LocationInfo locationInfo = LocationMgr.getDefaultLocation(userInfo.getLanguage());
                setPosition(locationInfo.getWorld(), locationInfo.getContinent(), locationInfo.getCountry(), locationInfo.getProvince(), locationInfo.getCity());
            }else {
                if (!StringUtil.isNullOrEmpty(ip)) {
                    LocationInfo locationInfo = LocationMgr.getLocationInfoByIp(ip, userInfo.getLanguage());
                    setPosition(locationInfo.getWorld(), locationInfo.getContinent(), locationInfo.getCountry(), locationInfo.getProvince(), locationInfo.getCity());
                }
            }
        }



        ServerInfo serverInfo = ServerListMgr.getServerInfo(GameServer.getInstance().getServerId());
        if (serverInfo != null) {
            if (eChannelType.isMainLandChannel(serverInfo.getChannelId())) {
                String location = "未知";
                try {
                    long userId = userInfo.getUserId();
                    if (WhiteListLocationMgr.isWhiteLocationUser(userId)) {
                        location = UserMgr.getIpLocation(userInfo.getUserId());
                        userInfo.setIpLocation(location);
                    }else {
                        GameServer.getSqlCommandExecutor().execute(() -> {
                                    String hLocation = "未知";
                                    try {

                                        hLocation = HttpHelper.doGet("https://login-cno.ngty556.com/Web/ip/location?ip=" + ip, "UTF-8");
                                    } catch (Exception e) {

                                    }
                                    Set<String> chinaLocationSet = new HashSet<>();
                                    chinaLocationSet.add("湖南");
                                    chinaLocationSet.add("湖北");
                                    chinaLocationSet.add("河南");
                                    chinaLocationSet.add("山东");
                                    chinaLocationSet.add("江西");
                                    chinaLocationSet.add("安徽");
                                    chinaLocationSet.add("浙江");
                                    chinaLocationSet.add("江苏");
                                    chinaLocationSet.add("黑龙江");
                                    chinaLocationSet.add("吉林");
                                    chinaLocationSet.add("辽宁");
                                    chinaLocationSet.add("山西");
                                    chinaLocationSet.add("河北");
                                    chinaLocationSet.add("福建");
                                    chinaLocationSet.add("西藏");
                                    chinaLocationSet.add("宁夏");
                                    chinaLocationSet.add("广西");
                                    chinaLocationSet.add("内蒙古");
                                    chinaLocationSet.add("台湾");
                                    chinaLocationSet.add("青海");
                                    chinaLocationSet.add("甘肃");
                                    chinaLocationSet.add("陕西");
                                    chinaLocationSet.add("云南");
                                    chinaLocationSet.add("四川");
                                    chinaLocationSet.add("贵州");
                                    chinaLocationSet.add("海南");
                                    chinaLocationSet.add("广东");
                                    chinaLocationSet.add("澳门");
                                    chinaLocationSet.add("香港");
                                    chinaLocationSet.add("重庆");
                                    chinaLocationSet.add("上海");
                                    chinaLocationSet.add("天津");
                                    chinaLocationSet.add("北京");
                                    chinaLocationSet.add("新疆");
                                    for (String name : chinaLocationSet) {
                                        if (hLocation != null && hLocation.contains(name)) {
                                            hLocation = name;
                                        }
                                    }
                                    if (Objects.equals("共享地址", hLocation) || hLocation == null) {
                                        hLocation = "未知";
                                    }
                                    GamePlayer onlinePlayer = GamePlayerMgr.getOnlinePlayer(userId);
                                    if (onlinePlayer != null) {
                                        UserInfo info = onlinePlayer.getModule(PlayerModule.class).getUserInfo();
                                        info.setIpLocation(hLocation);
                                        PlayerProto.PlayerDataTempMsg.Builder msg = PlayerPb.parsePlayerDataTempMsg(info, onlinePlayer.getModule(AttributeModule.class).getUserAttributeMap());
                                        if (null != msg) {
                                            onlinePlayer.sendPacket(Protocol.U_PLAYER_DATA, msg);
                                        }
                                    }
                                }
                        );
                    }
                } catch (Exception e) {

                }

            }
        }

    }

    int getHeartAddition(){
        return userInfo.getHeartCount() * GameConfig.HEART_ADDITION_EFFECT;
    }

    public void onTitleChange(){
        //检测系统解锁
        checkSystemOpen();
        //刷新全部门客实力
        player.getModule(PatronsModule.class).onPatronsChange(null);
        //子嗣席位解锁
        player.getModule(ChildModule.class).checkChildSiteUnlock(true);
        //寻宝检测矿场开启
        player.getModule(MineWarModule.class).checkMineRefugeInit();
        //检测是否解锁汴梁达人
        player.getModule(RecallPlayerModule.class).initSystem();
        //优惠券
        notifyCouponEvent();
        //QQ游戏大厅特权活动
        player.getModule(QQPrivilegeActivityModule.class).onTitleChange();
    }

    public void onUserInfoChange(){
        //商会信息变化
        String unionUid = userInfo.getUnionUid();
        if(!StringUtils.isNullOrEmpty(unionUid)){
            //CrossUnionMgr.updateMemberInfo(player, unionUid);
        }
        //榜单变化
        RankMgr.changeUserInfo(player.getUserId());
        //盐场榜单变化
        OreWarActivityRankMgr.changeUserInfo(player.getUserId());
        //乔迁风云变化
        player.getModule(EstateWarModule.class).userInfoChange(false);

        //刷新盐场坑位玩家基础信息
        List<Long> userIdList = new ArrayList<>();
        userIdList.add(player.getUserId());
        OreWarMgr.refreshCrossOreStation(userIdList);
        //招商项目玩家基本信息
        player.getModule(ZsModule.class).syncPlayerBaseInfoToCross2();
        // 同步榷场玩家基本信息
        MonopolyMarketMgr.addNeedUploadUserInfo(player);
        NewMonopolyMarketMgr.addNeedUploadUserInfo(player);
        SeacraftSouthSeaMgr.attemptUpdateUnionMasterInfo(player);
        UnionMember unionMember = CrossUnionMgr.getUnionMember(player.getUserId());
        if (unionMember != null && unionMember.getPosition() == eUnionPosition.Master.getValue()) {
            //如果是会长，会长信息也要更新下
            CrossUnionInfo unionInfo = CrossUnionMgr.getUnionInfo(unionUid);
            if (unionInfo != null) {
                RankMgr.changeUnionRank(unionInfo);
                UnionActivityMgr.changeUnionInfo(unionInfo);
            }
        }
        UserMgr.addNeedUpdateToCrossMap(player.getUserId(),userInfo);
        //Redis角色信息
        if(ChannelConfig.USER_INFO_USE_REDIS == 1) {
            try {
                RedisManger.getRedisUtil().setString("user_base_info:" + player.getUserId(), JSON.toJSONString(UserMgr.parseUserBaseInfo(userInfo, GameServer.getInstance().getServerId())));
            } catch (Exception e) {
                log.error("update user info to redis fail,userId:{},error:", player.getUserId(), e);
            }
        }
    }

    public void changeDecoration(int decorationType, int decorationId, boolean changeRole) {
        UserMgr.checkPlayerDecorationOverTime(userInfo, false);
        String decoration = userInfo.getDecoration();
        List<Integer> dataList = StringUtils.stringToIntegerList(decoration, DecorationMgr.SPLIT_SEPARATOR);
        while (dataList.size() < 7) {
            dataList.add(0);
        }
        if (dataList.get(0) == 0) {
            dataList.set(0, DecorationMgr.getDefaultDecorationId(eDecorationType.HeadIcon.getValue(), player.getUserInfo().getSex()));
        }
        if (dataList.get(1) == 0) {
            dataList.set(1, DecorationMgr.getDefaultDecorationId(eDecorationType.HeadFrame.getValue(), player.getUserInfo().getSex()));
        }
        if (dataList.get(5) == 0) {
            dataList.set(5, DecorationMgr.getDefaultDecorationId(eDecorationType.ChatBubble.getValue(), player.getUserInfo().getSex()));
        }
        if (decorationType == eDecorationType.HeadIcon.getValue()) {
            dataList.set(0, decorationId);
            player.notifyListener(eGamePlayerEventType.ChangeHeadIconTimes.getValue(), 1);
            if (changeRole) {
                dataList.set(3, decorationId);
            }
        } else if (decorationType == eDecorationType.HeadFrame.getValue()) {
            dataList.set(1, decorationId);
        } else if (decorationType == eDecorationType.HonoraryTitle.getValue()) {
            dataList.set(2, decorationId);
        } else if (decorationType == eDecorationType.Costume.getValue()) {
            dataList.set(4, decorationId);
        } else if (decorationType == eDecorationType.ChatBubble.getValue()) {
            dataList.set(5, decorationId);
        } else if (decorationType == eDecorationType.ChatTitle.getValue()) {
            dataList.set(6, decorationId);
        }
        decoration = StringUtils.listToString(dataList, DecorationMgr.SEPARATOR);
        userInfo.setDecoration(decoration);
        onUserInfoChange();
    }

    /**
     * 修改角色形象
     */
    public int changeRole(int headId, int costumeId) {
        // 判断是否解锁
        if (player.getTitleId() < GameConfig.ROLE_CHOOSE_OPEN_COND) {
            // 等级不足
            return GameErrorCode.E_CHANGE_ROLE_NOT_OPEN;
        }
        // 判断消耗
        Property cost = PropertyHelper.parseStringToProperty(GameConfig.ROLE_CHOOSE_COST);
        if (!player.getModule(CurrencyModule.class).removeCurrency(cost, eLogMoneyType.System, eLogMoneyType.ChangeRoleCost)) {
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }
        Property configReward = new Property();
        // 需要获得1~当前级所有的装饰
        for (int i = 1; i <= player.getTitleId(); i++) {
            TitleInfo titleInfo = TitleMgr.getTitleInfo(i);
            if (player.getUserInfo().getSex() == eSexType.MALE.getValue()) {
                configReward.addProperty(titleInfo.getMaleReward());
            } else if (player.getUserInfo().getSex() == eSexType.FEMALE.getValue()) {
                configReward.addProperty(titleInfo.getFemaleReward());
            }
        }
        DecorationModule decorationModule = player.getModule(DecorationModule.class);
        // 过滤下
        Property reward = new Property();
        for (Map.Entry<Integer, BigInteger> entry : configReward.getGoods().entrySet()) {
            Integer decorationId = entry.getKey();
            if (!GoodsMgr.isDecorationGoods(decorationId)) {
                continue;
            }
            // 判断是否已存在
            UserDecoration userDecoration = decorationModule.getUserDecoration(decorationId);
            if (userDecoration != null) {
                continue;
            }
            reward.addProperty(new Property(entry.getKey(), entry.getValue()));
        }
        // 获得装饰
        player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.Title, eLogMoneyType.ChangeRoleReward);
        // 改头
        changeDecoration(eDecorationType.HeadIcon.getValue(), headId, true);
        // 身体形象
        changeDecoration(eDecorationType.Costume.getValue(), costumeId, true);
        DecorationProto.ChangeRoleRespMsg.Builder respMsg = DecorationProto.ChangeRoleRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setDecoration(player.getUserInfo().getDecoration());
        player.sendPacket(Protocol.U_CHANGE_ROLE, respMsg);
        return 0;
    }

    /**
     * 更改徽章信息
     * @param badge 徽章信息
     */
    public int changeBadge(String badge) {
        // 获取旧的勋章数据(日志用)
        String oldBadge = userInfo.getBadge();
        // 格式 徽章id,徽章类型|徽章id,徽章类型|徽章id,徽章类型 => 1001,1|1004,2|1003,3
        List<String> badgeList = StringUtils.stringToStringList(badge, "\\|");
        // 获取用户徽章信息
        Map<Integer, List<UserBadge>> userBadgeMap = player.getModule(BadgeModule.class).getUserBadgeMap();
        for (String badgeStr : badgeList) {
            String[] split = badgeStr.split(",");
            int badgeId = Integer.parseInt(split[0]);
            int badgeType = Integer.parseInt(split[1]);
            if (!userBadgeMap.containsKey(badgeType)) {
                // 徽章不存在
                return GameErrorCode.E_BADGE_NOT_EXIST;
            }
            if (userBadgeMap.get(badgeType).stream().noneMatch(userBadge -> userBadge.getBadgeId() == badgeId)) {
                // 徽章不存在
                return GameErrorCode.E_BADGE_NOT_EXIST;
            }
        }
        userInfo.setBadge(badge);
        onUserInfoChange();
        BadgeProto.ChangeBadgeShowRespMsg.Builder respMsg = BadgeProto.ChangeBadgeShowRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setBadge(badge);
        player.sendPacket(Protocol.U_BADGE_SHOW_CHANGE, respMsg);
        // 装载日志
        AutoLogMgr.add(new LogBadgeChange(player.getUserId(), oldBadge, badge, new Date()));
        return 0;
    }

    /**
     * 替换徽章信息
     *
     * @param badgeId    徽章id
     * @param badgeType  徽章类型
     * @param badgeIndex 徽章索引
     */
    public void replaceBadge(int badgeId, int badgeType, int badgeIndex) {
        // 格式 徽章id,徽章类型|徽章id,徽章类型|徽章id,徽章类型 => 1001,1|1004,2|1003,3
        String badge = userInfo.getBadge();
        List<String> badgeList = StringUtils.stringToStringList(badge, "\\|");
        badgeList.set(badgeIndex, badgeId + "," + badgeType);
        badge = StringUtils.listToString(badgeList, "|");
        userInfo.setBadge(badge);
        onUserInfoChange();
        PlayerProto.PlayerDataTempMsg.Builder msg = PlayerPb.parsePlayerDataTempMsg(userInfo, player.getModule(AttributeModule.class).getUserAttributeMap());
        if(null != msg) {
            player.sendPacket(Protocol.U_PLAYER_DATA, msg);
        }
    }

    public void checkSystemOpen() {
        for(BaseSystemOpen systemOpen : systemOpenList){
            systemOpen.checkSystemOpen();
        }
    }

    public void checkWingRoomSystemOpen() {
        for (BaseSystemOpen systemOpen : systemOpenList) {
            if (systemOpen.getSystemId() == eSystemId.WingRoom.getValue()) {
                systemOpen.checkSystemOpen();
            }
            //厢房命盘
            if (systemOpen.getSystemId() == eSystemId.Chakra.getValue()) {
                systemOpen.checkSystemOpen();
            }
        }
    }

    /**
     * 增加活动逗留时间
     * @param activityId
     * @param remainTime
     */
    public void addActivityRemainTime(int activityId, long remainTime){
        if(!activityRemainTimeMap.containsKey(activityId)){
            synchronized (activityRemainTimeMap){
                if(!activityRemainTimeMap.containsKey(activityId)){
                    ActivityRemainTime activityRemainTime = new ActivityRemainTime();
                    activityRemainTime.setActivityId(activityId);
                    ActivityInfo activityInfo = NormalActivityMgr.getActivityInfo(activityId);
                    if(null != activityInfo){
                        activityRemainTime.setActivityType(activityInfo.getType());
                        activityRemainTime.setActivityChildType(activityInfo.getChildType());
                    }
                    activityRemainTimeMap.put(activityId, activityRemainTime);
                }
            }
        }
        ActivityRemainTime activityRemainTime = activityRemainTimeMap.get(activityId);
        if(null != activityRemainTime) {
            activityRemainTime.setRemainTime(activityRemainTime.getRemainTime() + remainTime);
        }
    }

    public synchronized void saveActivityRemainTime(){
        for(ActivityRemainTime activityRemainTime : activityRemainTimeMap.values()) {
            AutoLogMgr.add(new LogActivityRemainTime(player.getUserId(), activityRemainTime.getActivityId(), activityRemainTime.getActivityType(),
                    activityRemainTime.getActivityChildType(), activityRemainTime.getRemainTime()));
        }
        activityRemainTimeMap.clear();
    }


    public void addSystemRemainTime(int systemId, long remainTime) {
        if (systemId != eSystemId.UnionCampWar.getValue() &&
                systemId != eSystemId.NewMonopolyMarket.getValue() &&
                systemId != eSystemId.Kuang.getValue()) {
            return;
        }
        int systemThisWeekId = GameConfig.getSystemThisWeekId();
        if (!systemRemainTimeMap.containsKey(systemId)) {
            synchronized (systemRemainTimeMap) {
                if (!systemRemainTimeMap.containsKey(systemId)) {
                    systemRemainTimeMap.put(systemId, new ConcurrentHashMap<>());
                    Map<Integer, SystemRemainTime> remainTimeMap = systemRemainTimeMap.get(systemId);
                    if (!remainTimeMap.containsKey(systemThisWeekId)) {
                        SystemRemainTime systemRemainTime = new SystemRemainTime();
                        systemRemainTime.setSystemId(systemId);
                        systemRemainTime.setId(systemThisWeekId);
                        systemRemainTimeMap.get(systemId).put(systemThisWeekId, systemRemainTime);
                    }
                }
            }
        }
        SystemRemainTime systemRemainTime = systemRemainTimeMap.get(systemId).get(systemThisWeekId);
        if (systemRemainTime != null) {
            systemRemainTime.setRemainTime(systemRemainTime.getRemainTime() + remainTime);
        }
    }

    public synchronized void saveSystemRemainTime() {
        for (Map<Integer, SystemRemainTime> remainTimeMap : systemRemainTimeMap.values()) {
            for (SystemRemainTime remainTime : remainTimeMap.values()) {
                AutoLogMgr.add(new LogSystemRemainTime(
                        player.getUserId(),
                        remainTime.getSystemId(),
                        remainTime.getId(),
                        remainTime.getRemainTime(),
                        System.currentTimeMillis()
                ));
            }
        }
    }

    private void addUserTitleUpgrade(int titleId, long upgradeTime){
        UserTitleUpgrade userTitleUpgrade = new UserTitleUpgrade();
        userTitleUpgrade.setUserId(player.getUserId());
        userTitleUpgrade.setTitleId(titleId);
        userTitleUpgrade.setUpgradeTime(upgradeTime);
        userTitleUpgrade.setInsertOption();
        userTitleUpgradeMap.put(userTitleUpgrade.getTitleId(), userTitleUpgrade);
    }

    public Map<Integer, UserTitleUpgrade> getUserTitleUpgradeMap() {
        return new ConcurrentHashMap<>(userTitleUpgradeMap);
    }

    private void syncSystemInfo(List<UserSystemInfo> dataList, boolean isLogin){
        if(isLogin){
            player.sendPacket(Protocol.U_SYSTEM_PREVIEW_LIST, PlayerPb.parseSystemOpenPreviewListMsg(dataList));
        }else {
            player.sendPacket(Protocol.U_SYSTEM_PREVIEW_SYNC, PlayerPb.parseSystemOpenPreviewListMsg(dataList));
        }
    }

    public void syncSystemInfo(UserSystemInfo data){
        if(null != data){
            List<UserSystemInfo> syncList = new ArrayList<>();
            syncList.add(data);
            syncSystemInfo(syncList, false);
        }
    }

    private UserSystemInfo getUserSystemInfo(int systemId){
        return userSystemInfoMap.get(systemId);
    }

    public int getSystemPreviewReward(int systemId){
        UserSystemInfo userSystemInfo = getUserSystemInfo(systemId);
        if(null != userSystemInfo && userSystemInfo.isGetPreviewReward()){
            return GameErrorCode.E_SYSTEM_PREVIEW_IS_REWARD;
        }
        if(!SystemOpenMgr.systemOpen(player, systemId)){
            return GameErrorCode.E_SYSTEM_NO_OPEN;
        }
        // 废弃
//        Property reward = ConfigMgr.getSystemPreviewReward(systemId);
        SystemOpenInfo systemOpenInfo = SystemOpenMgr.getSystemOpenInfo(systemId);
        if (systemOpenInfo == null) {
            return GameErrorCode.E_SYSTEM_NO_OPEN;
        }
        if (systemOpenInfo.getShowReward() == null || systemOpenInfo.getShowReward().isNothing()) {
            return GameErrorCode.E_SYSTEM_PREVIEW_REWARD_NO_FOUND_SYSTEM;
        }
        if(null == userSystemInfo){
            userSystemInfo = new UserSystemInfo();
            userSystemInfo.setUserId(player.getUserId());
            userSystemInfo.setSystemId(systemId);
            userSystemInfo.setInsertOption();
            userSystemInfoMap.put(systemId, userSystemInfo);
        }
        userSystemInfo.setGetPreviewReward(true);
        player.getModule(CurrencyModule.class).addCurrency(systemOpenInfo.getShowReward(), eLogMoneyType.System, eLogMoneyType.SystemPreviewGetReward);
        syncSystemInfo(userSystemInfo);
        PlayerProto.SystemOpenPreviewRewardRespMsg.Builder respMsg = PlayerProto.SystemOpenPreviewRewardRespMsg.newBuilder();
        respMsg.setRet(0);
        respMsg.setReward(PropertyHelper.parsePropertyToString(systemOpenInfo.getShowReward()));
        player.sendPacket(Protocol.U_SYSTEM_PREVIEW_REWARD, respMsg);
        return 0;
    }

    public void notifyCouponEvent(){
        CouponNotifyArgs notifyArgs = new CouponNotifyArgs();
        notifyArgs.setLogin(false);
        player.notifyListener(eGamePlayerEventType.CouponTrigger.getValue(), notifyArgs);
    }

    /**
     * 幸运夺宝
     */
    public List<Property> doTurntableLottery(int type,int times,Property consume){
        List<Property> rewardList = new ArrayList<>();
        AttributeModule attributeModule = player.getModule(AttributeModule.class);
        Property reward = new Property();
        for(int i = 0; i < times; i++){
            Property property = new Property();
            int notice;
            long oldValue = attributeModule.getAttribute(ePlayerAttrType.LuckyValue);
            attributeModule.addAttribute(ePlayerAttrType.LuckyValue, 1);
            if(attributeModule.getAttribute(ePlayerAttrType.LuckyValue) > GameConfig.TURNTABLE_MAX_LUCKY_VALUE){
                attributeModule.setAttribute(ePlayerAttrType.LuckyValue, 0);
                attributeModule.addAttribute(ePlayerAttrType.TurntableLotteryLuckyTimes, 1);
                property.addProperty(GameConfig.TURNTABLE_LUCKY_VALUE_MAX_GET_ITEM, BigInteger.ONE);
                notice = 1;
                attributeModule.addAttribute(ePlayerAttrType.TurntableTotalFullLuckyTimes, 1);
                //成就、任务
                player.notifyListener(eGamePlayerEventType.TurntableTotalFullLuckyTimes.getValue(), attributeModule.getAttribute(ePlayerAttrType.TurntableTotalFullLuckyTimes));
            }else {
                if (ConfigMgr.isTurntableLotteryLucy((int) attributeModule.getAttribute(ePlayerAttrType.TurntableLotteryLuckyTimes))) {
                    attributeModule.addAttribute(ePlayerAttrType.TurntableLotteryLuckyTimes, 1);
                    property.addProperty(GameConfig.TURNTABLE_LUCKY_VALUE_MAX_GET_ITEM, BigInteger.ONE);
                    notice = 1;
                } else {
                    int goodsBagId;
                    if (attributeModule.getAttribute(ePlayerAttrType.TurntableLotteryTotalTimes) < GameConfig.TURNTABLE_USE_HIGH_LUCKY_TIMES) {
                        goodsBagId = GameConfig.GAME_BOX_TURNTABLE_HIGH_LUCKY;
                    } else {
                        goodsBagId = GameConfig.GAME_BOX_TURNTABLE_NORMAL_LUCKY;
                    }
                    OpenGoodsBagResult openResult = GoodsBagMgr.getRandomGoods(goodsBagId);
                    notice = openResult.getNotice();
                    property = openResult.getReward();
                    for (Map.Entry<Integer, BigInteger> dataEntry : property.getGoods().entrySet()) {
                        if (dataEntry.getKey() == GameConfig.TURNTABLE_LUCKY_VALUE_MAX_GET_ITEM) {
                            attributeModule.addAttribute(ePlayerAttrType.TurntableLotteryLuckyTimes, 1);
                            break;
                        }
                    }
                }
            }
            attributeModule.addAttribute(ePlayerAttrType.TurntableLotteryTotalTimes, 1);
            rewardList.add(property);
            reward.addProperty(property);
            AutoLogMgr.add(new LogTurntableReward(player.getUserId(), 1, oldValue, attributeModule.getAttribute(ePlayerAttrType.LuckyValue), PropertyHelper.parsePropertyToString(property)));
            //增加抽奖记录
            if(1 == notice){
                TurntableMgr.addTurntableLotteryRecord(player, property);
            }
        }
        //奖励入袋
        player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.Activity, eLogMoneyType.TurntableLottery);
        //成就、任务
        player.notifyListener(eGamePlayerEventType.TurntableLotteryTotalTimes.getValue(), attributeModule.getAttribute(ePlayerAttrType.TurntableLotteryTotalTimes));
        //4.8.1 新服福利活动抽奖次数
        if (SystemOpenMgr.systemOpen(player, eSystemId.NewServerWelfareActivity.getValue()) && NewServerWelfareMgr.checkActivityOntime(eNewServerWelfareActivityType.DrawTimes.getValue())) {
            player.notifyListener(eGamePlayerEventType.NewServerWelfareDrawTimes.getValue(), times);
        }

        //不足下次升级
        if (!player.getModule(CurrencyModule.class).currencyIsEnough(consume)) {
            player.notifyListener(eGamePlayerEventType.RechargeLotteryTimesNew.getValue(), 0);
        }

        //幸运夺宝埋点
        DataAnalyticsMgr.trackTurntableLottery(player, type, rewardList, consume);
        return rewardList;
    }


}
